package cn.wei.sdd.core.service.impl;

import cn.wei.sdd.core.pojo.entity.ServiceArea;
import cn.wei.sdd.core.mapper.ServiceAreaMapper;
import cn.wei.sdd.core.pojo.vo.ServiceAreaVO;
import cn.wei.sdd.core.service.ServiceAreaService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 服务区域表 服务实现类
 * </p>
 *
 * @author Wei
 * @since 2021-11-21
 */
@Service
public class ServiceAreaServiceImpl extends ServiceImpl<ServiceAreaMapper, ServiceArea> implements ServiceAreaService {

    @Autowired
    private ServiceAreaService serviceAreaService;
    @Override
    public List<ServiceAreaVO> listVO() {
        return baseMapper.listVO();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateServiceArea(List<ServiceAreaVO> areaVOList, Long userId) {
        //删除原来的记录
        QueryWrapper<ServiceArea> serviceAreaQueryWrapper = new QueryWrapper<>();
        baseMapper.delete(serviceAreaQueryWrapper);

        //添加新
        baseMapper.insertBatch(areaVOList);

    }

    @Override
    public Boolean isInRange(ServiceAreaVO serviceAreaVO) {
          /*
             aLon: double 经度
             aLat: double 纬度
             pointList: list [{latitude: 22.22, longitude: 113.113}...]
             多边形点的顺序需根据顺时针或逆时针，不能乱

              判断一个点向左的射线跟一个多边形的交叉点有几个，如果结果为奇数的话那么说明这个点落在多边形中，反之则不在。

             该程序的思路是从A点出发向左做一条水平射线（平行于x轴，向X轴的反方向），判断与各边是否有焦点。
            dLon1, dLon2, dLat1, dLat2分别表示边的起点和终点的经度和纬度（x轴和y轴）。
            先判断A点是否在边的两端点d1和d2的水平平行线之间，不在则不可能有交点，继续判断下一条边。
            在之间则说明可能与A点向左的射线有交点，接下来利用几何方法得到A点的水平直线与该边交点的x坐标。
            然后判断交点的x坐标在A点的左侧还是右侧，左侧则总交点数加一，右侧则不在A点左射线上，继续判断下一条边。

        */
        Double aLon = serviceAreaVO.getLng();
        Double aLat = serviceAreaVO.getLat();
        System.out.println();
        List<ServiceArea> pointList = serviceAreaService.list();
        int iSum = 0;
        int iCount = pointList.size();

        if(iCount < 3) {
            return false;
        }
        //  待判断的点(x, y) 为已知值
        double y = aLon;
        double x =aLat;
        double y2;
        double x2;
        for(int i = 0; i < iCount; i++) {
            double y1 = pointList.get(i).getLatitude();
            double x1 = pointList.get(i).getLongitude();
            if(i == iCount - 1) {
                y2 = pointList.get(0).getLatitude();
                x2 = pointList.get(0).getLongitude();
            } else {
                y2 = pointList.get(i + 1).getLatitude();
                x2 =  pointList.get(i + 1).getLongitude();
            }
            // 当前边的 2 个端点分别为 已知值(x1, y1), (x2, y2)
            if (((y >= y1) && (y < y2)) || ((y >= y2) && (y < y1))) {
                //  y 界于 y1 和 y2 之间
                //  假设过待判断点(x, y)的水平直线和当前边的交点为(x_intersect, y_intersect)，有y_intersect = y
                // 则有（2个相似三角形，公用顶角，宽/宽 = 高/高）：|x1 - x2| / |x1 - x_intersect| = |y1 - y2| / |y1 - y|
                if (Math.abs(y1 - y2) > 0) {
                  double x_intersect = x1 - ((x1 - x2) * (y1 - y)) / (y1 - y2);
                    if(x_intersect < x) {
                        iSum += 1;
                    }
                }
            }
        }
        if(iSum % 2 != 0) {
            return true;
        }else {
            return false;
        }

    }

}
